#include "Panel.h"

using namespace GUIToolkit;

UIElement::UIElement(float x, float y, float width, float height, LPCWSTR name)
	: name(L"")
	, rect(x, y, width, height)
	, visible(true)
	, hittest(true)
	, cliptobound(true)
	, clip(NULL)
	, layoutenable(true)
	, layoutinfo()
	, padding()
	, root(NULL)
	, parent(NULL)
{
	if(name != NULL) this->name = name;
}

Panel* UIElement::GetRoot()
{ 
	if(this->root == NULL && this->GetParent() != NULL)
	{
		this->root = this->GetParent();
		while(this->root != NULL && this->root->GetParent() != NULL)
			this->root = this->root->GetParent();
	}
	return this->root;
}

void UIElement::GetTransform( Matrix* m )
{
	m->Reset();
	auto ui = this;
	while(ui != NULL && ui->GetParent() != NULL)
	{
		auto pt = ui->GetPosition();
		m->Translate(-pt.X, -pt.Y);
		ui = ui->GetParent();
	}
}

void UIElement::OnPropertyChanging(PROPERTY p)
{
	this->PropertyChanging((void*)p);
}

void UIElement::OnPropertyChanged(PROPERTY p)
{
	this->PropertyChanged((void*)p);
	if(p != PROPERTY::UI_TOOLTIP)
	{
		if(this->parent != NULL)
		{
			if(p == PROPERTY::UI_LAYOUTENABLE || p == PROPERTY::UI_LAYOUTINFO)
				this->parent->Layout();

			if(p == PROPERTY::UI_POSITION || p == PROPERTY::UI_SIZE)
			{
				static RectF oldrect;
				oldrect.Width++;
				oldrect.Height++;
				this->parent->Update(&oldrect);
				oldrect = this->rect;
			}
		}
		this->Update();
	}
}

void UIElement::OnPaintBackground( Graphics* g )
{
	auto back = this->GetBackground();
	if(back != NULL)
	{
		g->FillRectangle(back, RectF(PointF(), this->GetSize()));
	}
}

void UIElement::OnPaintForeground( Graphics* g )
{

}

const Brush* UIElement::GetForeground() const
{
	if(this->foreground != NULL)
		return this->foreground;
	else if(this->parent != NULL)
		return this->parent->GetForeground();
	else
		return NULL;
}

bool UIElement::HandleMessage( MESSAGE msg, void* param )
{
	switch(msg)
	{
	case MESSAGE::MSG_ROOT:
		{
			auto ro = this->root;     //old
			this->root = NULL;        //refresh
			auto rn = this->GetRoot();//new
			if(rn != ro)
			{
				this->root = ro;
				this->OnPropertyChanging(PROPERTY::UI_ROOT);
				this->root = rn;
				this->OnPropertyChanged(PROPERTY::UI_ROOT);
			}
		}
		break;
	case MESSAGE::MSG_PARENT:
		this->OnPropertyChanging(PROPERTY::UI_PARENT);
		this->parent = (Panel*)param;
		this->OnPropertyChanged(PROPERTY::UI_PARENT);
		break;
	case MESSAGE::MSG_FOCUS:
		this->OnPropertyChanged(PROPERTY::UI_FOCUS);
		break;
	case MESSAGE::MSG_MOUSE:
		{
			auto e = (MouseEventArgs*)param;
			if(e->Action == MouseAction::ENTER)
			{
				this->mouseover = true;
				::SetCursor(::LoadCursor(NULL, IDC_ARROW));
			}
			else if(e->Action == MouseAction::LEAVE)
				this->mouseover = false;

			if(e->Action == MouseAction::ENTER || e->Action == MouseAction::LEAVE)
				this->OnPropertyChanged(PROPERTY::UI_MOUSEOVER);

			this->OnMouseEvent(e);
		}
		break;
	case MESSAGE::MSG_KEYBROAD:
		this->OnKeyEvent((KeyEventArgs*)param);
		break;
	}
	return false;
}

void UIElement::Update(RectF* rect)
{
	if( !this->IsVisible() ) return;
	auto parent = this->GetParent();
	if(parent == NULL) return;

	RectF real = this->GetRegion();

	if( rect != NULL && !rect->IsEmptyArea() )
	{
		RectF r = *rect;
		r.Offset(real.X, real.Y);
		real.Intersect(r);
	}

	parent->Update(&real);
}

UIElement* UIElement::HitTest(PointF* p)
{
	if(!this->hittest) return NULL;
	SizeF size = this->GetSize();
	if(p->X >= 0 && p->X < size.Width && p->Y >= 0 && p->Y < size.Height) 
		return this;
	else
		return NULL;
}

void UIElement::SetRegion( float x, float y, float width, float height ) 
{
	if(this->rect.X != x || this->rect.Y != y)
	{
		this->OnPropertyChanging(PROPERTY::UI_POSITION);
		this->rect.X = x;
		this->rect.Y = y;
		this->OnPropertyChanged(PROPERTY::UI_POSITION);
	}

	if(this->rect.Width != width || this->rect.Height != height)
	{
		this->OnPropertyChanging(PROPERTY::UI_SIZE);
		this->rect.Width = width; 
		this->rect.Height = height;
		this->OnPropertyChanged(PROPERTY::UI_SIZE);
	}
}

UIElement::~UIElement(void) 
{ 
	SafeRelease(background);
	SafeRelease(foreground);
}


//---Control---------------------
void Control::OnMouseEvent(MouseEventArgs* e)
{
	switch(e->Action)
	{
		case MouseAction::ENTER:
			this->mouseover = true;
			break;
		case MouseAction::LEAVE:
			this->mouseover = false;
			break;
	}

	this->MouseEvent(e);
}

void Control::OnKeyEvent(KeyEventArgs* e)
{
	this->KeyEvent(e);
}

Control::~Control(void) 
{ 

}